﻿using System;
using System.Collections.Generic;
using System.Text;

namespace WebParser
{
    /// <summary>
    /// 此版本速度過慢
    /// </summary>
    public class HttpContentParser1
    {
        public event EventHandler<ContentEventArgs> ContentReceived;
        protected virtual void OnContentReceiver(ContentEventArgs e)
        {
            if (ContentReceived != null) ContentReceived(this, e);
        }

        private readonly string _boundary;
        private string _contentType;
        private int _contentLength;
        private readonly Encoding _enc = Encoding.ASCII;
        private readonly List<byte> _tmp;
        private Action<byte> _p;

        public HttpContentParser1(string boundary)
        {
            _boundary = boundary;
            _tmp = new List<byte>();
            Reset();
        }

        public void Parse(byte b)
        {
            _p(b);
        }
        public void Reset()
        {
            _tmp.Clear();
            SwitchTo(ReadBoundary);
        }
        private void SwitchTo(Action<byte> function)
        {
            //var source = (_p == null) ? "{EMPTY}" : _p.Method.Name;
            //var target = (function == null) ? "{EMPTY}" : function.Method.Name;
            //Debug.WriteLine(string.Format("{0} => {1}", source, target));
            _p = function;
        }
        private void ReadBoundary(byte b)
        {
            if (b == '\r') return;
            if (b == '\n')
            {
                var line = _enc.GetString(_tmp.ToArray());
                if (line == _boundary)
                    SwitchTo(ReadFrameHeader);
                _tmp.Clear();
                return;
            }
            _tmp.Add(b);
        }
        private void ReadFrameHeader(byte b)
        {
            if (b == '\r') return;
            if (b == '\n')
            {
                if (_tmp.Count < 1)
                {
                    SwitchTo(ReadFrameData);
                    return;
                }
                var line = _enc.GetString(_tmp.ToArray());
                var index = line.IndexOf(": ");
                if (index > -1)
                {
                    var key = line.Substring(0, index);
                    switch (key)
                    {
                        case "Content-Type":
                            _contentType = line.Substring(index + 2);
                            break;
                        case "Content-Length":
                            int len;
                            if (int.TryParse(line.Substring(index + 2), out len))
                                _contentLength = len;
                            break;
                    }
                }
                _tmp.Clear();
                return;
            }
            _tmp.Add(b);
        }
        private void ReadFrameData(byte b)
        {
            _tmp.Add(b);
            if (_tmp.Count < _contentLength) return;

            var e = new ContentEventArgs(_tmp.ToArray(), _contentType, _contentLength);
            OnContentReceiver(e);
            _contentType = null;
            _contentLength = -1;

            _tmp.Clear();
            SwitchTo(ReadBoundary);
        }
    }
}